package com.sanploy.wechat.service.impl;

import com.google.gson.Gson;
import com.sanploy.common.enums.Meta;
import com.sanploy.common.vo.BaseException;
import com.sanploy.wechat.conf.Constant;
import com.sanploy.wechat.dto.PayInfo;
import com.sanploy.wechat.dto.PayNotify;
import com.sanploy.wechat.dto.PaySign;
import com.sanploy.wechat.dto.WeChatLoginBack;
import com.sanploy.wechat.service.WechatSmallService;
import com.sanploy.wechat.util.CommonUtil;
import com.sanploy.wechat.util.TimeUtils;
import com.sanploy.wechat.util.WechatRetrofitUtil;
import com.thoughtworks.xstream.XStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * Created by zhu yingzhi on 2017/9/21.
 */
@Service
public class WechatSmallServiceImpl implements WechatSmallService{

    private Gson gson = new Gson();


    /**
     * 登陆 如果没有当前用户就注册 如果有则直接存储在session中
     * @param code
     * @return
     * @throws IOException
     */
    @Override
    public WeChatLoginBack login(String code) throws IOException, BaseException {
        try {
            return gson.fromJson(WechatRetrofitUtil.login(Constant.APPID,code, Constant.APPSCRIPT), WeChatLoginBack.class);
        }catch (Exception e){
            throw  new BaseException(Meta.WechatFail);
        }
    }

    @Override
    public PaySign unifiedOrder(String openId,double price,String orderId) throws NoSuchAlgorithmException, IOException {
        Date date = new Date();
        String timeStart = TimeUtils.getFormatTime(date, Constant.TIME_FORMAT);
        String timeExpire = TimeUtils.getFormatTime(TimeUtils.addDay(date, Constant.TIME_EXPIRE), Constant.TIME_FORMAT);

        PayInfo payInfo = new PayInfo();
        payInfo.setAppid(Constant.APPID);
        payInfo.setMch_id(Constant.Pay_KEY);
        payInfo.setDevice_info("WEB");
        payInfo.setNonce_str(CommonUtil.getRandomOrderId());
        //默认即为MD5
        payInfo.setSign_type("MD5");
        payInfo.setBody("安安妈妈蛋糕烘培店购买支付");
        payInfo.setAttach("安安妈妈蛋糕烘培店购买支付");
        payInfo.setOut_trade_no(orderId);
        System.out.println("总价格:"+price);
        int x = (int) (price*100);
        payInfo.setTotal_fee(x);
        payInfo.setSpbill_create_ip("127.0.0.1");
        payInfo.setTime_start(timeStart);
        payInfo.setTime_expire(timeExpire);
        payInfo.setNotify_url(Constant.URL_NOTIFY);
        payInfo.setTrade_type("JSAPI");
        payInfo.setLimit_pay("no_credit");
        payInfo.setOpenid(openId);

        payInfo.setSign(getSign(payInfo));


        String xml = CommonUtil.payInfoToXML(payInfo);

        xml = xml.replace("__", "_");

        String returnXml = WechatRetrofitUtil.unifiedOrder(xml);


        if (returnXml.indexOf("FAIL") != -1) {
            return new PaySign();
        }
        Map<String, String> result = CommonUtil.doXMLParse(returnXml);

//        Map<String, String> result = CommonUtil.parseXml(buffer.toString());
        String prepay_id = result.get("prepay_id");
        String packages = "prepay_id=" + prepay_id;


        PaySign paySign = new PaySign(Constant.APPID,String.valueOf(System.currentTimeMillis() / 1000L),
                UUID.randomUUID().toString().substring(0,18),packages,"MD5");
        paySign.setPaySign(paySign(paySign));
        return paySign;
    }

    //TODO 验证微信签名
    @Override
    public PayNotify notifyPay(String xml) {
        XStream xs = new XStream();
        xs.processAnnotations(new Class[]{PayNotify.class});
        PayNotify payNotify = (PayNotify)xs.fromXML(xml);

        return payNotify;
    }


    private String getSign(PayInfo payInfo) throws NoSuchAlgorithmException {
        StringBuffer sb = new StringBuffer();
        sb.append("appid=" + payInfo.getAppid())
                .append("&attach=" + payInfo.getAttach())
                .append("&body=" + payInfo.getBody())
                .append("&device_info=" + payInfo.getDevice_info())
                .append("&limit_pay=" + payInfo.getLimit_pay())
                .append("&mch_id=" + payInfo.getMch_id())
                .append("&nonce_str=" + payInfo.getNonce_str())
                .append("&notify_url=" + payInfo.getNotify_url())
                .append("&openid=" + payInfo.getOpenid())
                .append("&out_trade_no=" + payInfo.getOut_trade_no())
                .append("&sign_type=" + payInfo.getSign_type())
                .append("&spbill_create_ip=" + payInfo.getSpbill_create_ip())
                .append("&time_expire=" + payInfo.getTime_expire())
                .append("&time_start=" + payInfo.getTime_start())
                .append("&total_fee=" + payInfo.getTotal_fee())
                .append("&trade_type=" + payInfo.getTrade_type())
                .append("&key=" + Constant.Pay_Script);

        System.out.println("排序后的拼接参数：" + sb.toString());

        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }
//<xml><appid><![CDATA[wxe12c695c9e5f31ac]]></appid><attach><![CDATA[支付测试4luluteam]]></attach><bank_type><![CDATA[CFT]]></bank_type><cash_fee><![CDATA[1]]></cash_fee><device_info><![CDATA[WEB]]></device_info><fee_type><![CDATA[CNY]]></fee_type><is_subscribe><![CDATA[N]]></is_subscribe><mch_id><![CDATA[1489616622]]></mch_id><nonce_str><![CDATA[2092088158]]></nonce_str><openid><![CDATA[oe7QQ0SdlZzgEzz6AUv-8H-eRsIw]]></openid><out_trade_no><![CDATA[2092088158]]></out_trade_no><result_code><![CDATA[SUCCESS]]></result_code><return_code><![CDATA[SUCCESS]]></return_code><sign><![CDATA[4678C792D65B8550DA3264DA7A9F4360]]></sign><time_end><![CDATA[20171009114511]]></time_end><total_fee>1</total_fee><trade_type><![CDATA[JSAPI]]></trade_type><transaction_id><![CDATA[4200000011201710097000539349]]></transaction_id></xml>
    private String paySign(PaySign paySign) throws NoSuchAlgorithmException {
        StringBuffer sb = new StringBuffer();
                sb.append("appId=" + paySign.getAppId())
                        .append("&nonceStr=" + paySign.getNonceStr())
                        .append("&package=" + paySign.getPackage1())
                        .append("&signType=" + paySign.getSignType())
                        .append("&timeStamp=" + paySign.getTimeStamp())
                .append("&key=" + Constant.Pay_Script);
        return CommonUtil.getMD5(sb.toString().trim()).toUpperCase();
    }


}
